#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include<pthread.h>
using namespace std;

enum LogLevel
{
    Debug = 0,
    Info,
    Warning,
    Error,
    Fatal
};
enum Style
{
    Screen = 10,
    FileOne,
    FileDiv
};

const Style &style = Screen;
const string &filename = "log";
const string &log_dir = "log";
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
string GetLogLevel(LogLevel level)
{
    switch (level)
    {
    case Debug:
        return "debug";
    case Info:
        return "info";
    case Warning:
        return "warning";
    case Error:
        return "error";
    case Fatal:
        return "fatal";
    default:
        return "unknown";
    }
}
string TimeTo_string()
{
    uint64_t current = time(nullptr);
    struct tm *cur = localtime((const time_t *)&current);
    char buffer_time[128];

    snprintf(buffer_time, sizeof(buffer_time),
             "%d-%d-%d %d:%d:%d",
             cur->tm_year + 1900, cur->tm_mon + 1, cur->tm_mday, cur->tm_hour, cur->tm_min, cur->tm_sec);
    return buffer_time;
}
class Log
{

private:
    // 日志的写入选择
    void WriteLog(const string &level, const string &message)
    {
        pthread_mutex_lock(&lock);
        switch (_style)
        {
        case Screen:
            cout << message << endl;
            break;
        case FileOne:
        {
            string log_name = log_dir;
            log_name += "/";
            log_name += _filename;
            log_name += ".all";
            WriteOne(log_name, message);
            break;
        }
        case FileDiv:
            WriteDiv(level, message);
            break;
        default:
            break;
        }
        pthread_mutex_unlock(&lock);
    }
    // 根据日志等级写入相应的多种文件
    void WriteDiv(const string &level, const string &message)
    {
        string log_name = log_dir;
        log_name += "/";
        log_name += _filename;
        log_name += ".";
        log_name += level;
        WriteOne(log_name, message);
    }
    // 写入相应的单个文件
    void WriteOne(const string &log_name, const string &message)
    {
        // 追加写入
        ofstream out(log_name, std::ios::app);
        if (!out.is_open())
            return;

        out.write(message.c_str(), message.size());
        out.close();
    }

public:
    Log()
        : _style(style), _filename(filename)
    {
        mkdir(log_dir.c_str(), 0775);
    }
    ~Log()
    {
    }
    // 选择
    void LogOption(Style s = style, const string &f = filename)
    {
        _style = s;
        _filename = f;
    }
    // 传入日志等级
    void LogMessage(LogLevel level, const char *format, ...)
    {
        // 获取可变参数的传入值
        char right_buffer[1024];
        va_list args;
        va_start(args, format);
        // args指向了可变参数部分
        vsnprintf(right_buffer, sizeof(right_buffer), format, args);

        va_end(args);

        // 日志等级、时间、进程pid获取
        char left_buffer[1024];
        string log_level = GetLogLevel(level);
        string AD_time = TimeTo_string();
        string string_pid = to_string(getpid());
        snprintf(left_buffer, sizeof(left_buffer), "[%s][%s][%s]",
                 log_level.c_str(), AD_time.c_str(), string_pid.c_str());

        string log_info = left_buffer;
        log_info += right_buffer;

        WriteLog(log_level, log_info);
    }

private:
    Style _style;
    string _filename;
};
// 在类中默认创建对象
Log lg;

class Conf
{
public:
    Conf()
    {
        // 配置设置为打印在屏幕上
        lg.LogOption(Screen);
    }
    ~Conf()
    {}
};

Conf conf;
